﻿/* -----------------------------------------------
PartyStart

a sample "mash up" application showcasing
Microsoft's Virtual Earth and Windows Live Contacts.

Developed for Microsoft by the fine folks
at LiveGadgets.net

----------------------------------------------- */

var ps; // partystarter instance
var myContactsEl; ///Windows Live Contact gadget lives here
var alphaClass; //for pushpin alpha compatability
var butContactsEl; //the "Reselect Contacts" button
var skipFindConfirmation; //only show "select a place to meet" dialog once

//define the "places"
var places = [];
var myPlace = {"title":"", "className":"otherPushpin", "query":"", "checked":false, "locs":[]};
places.push(myPlace);
places.push({"title":"Restaurants", "className":"restaurantPushpin", "query":"restaurant", "checked":true, "locs":[]});
places.push({"title":"Bars/Lounges", "className":"barPushpin", "query":"bar & lounge", "checked":true, "locs":[]});
places.push({"title":"Coffee Houses", "className":"coffeePushpin", "query":"coffee & tea", "checked":true, "locs":[]});
places.push({"title":"Bowling Alleys", "className":"bowlingPushpin", "query":"bowling", "checked":false, "locs":[]});
places.push({"title":"Movie Theaters", "className":"theaterPushpin", "query":"movie theater", "checked":false, "locs":[]});
places.push({"title":"Other", "className":"otherPushpin", "query":"", "checked":false, "locs":[]});


//get some help formatting strings
String.prototype.format=function(){
	var s=this;
	for (var i=0; i < arguments.length; i++){
		s=s.replace("{" + i + "}", arguments[i]);
	}
	return s;
};

function PartyStarter(mapToPushpinId) {
    var m_name;
    var m_email;
    var m_address;
    var m_indexToMap;
    var m_arrayOfUserData = null;
    var m_destination = null;
    this.contacts = null;

    var pinId=0; //unique ID counter
    
    var m_map = new VEMap(mapToPushpinId);
    m_map.ShowMessage=noop;
    m_map.LoadMap();
    this.map = m_map;
    

    //create a hidden map instance for geocoding
    var elMapGeocode = document.createElement("div");
    elMapGeocode.id = mapToPushpinId + '_geocode';
    elMapGeocode.style.position = 'absolute';
    elMapGeocode.style.height = '100px';
    elMapGeocode.style.width = '100px';
    elMapGeocode.style.visibility = 'hidden';
    document.getElementById(mapToPushpinId).appendChild(elMapGeocode);

    var m_mapGeocode = new VEMap(elMapGeocode.id);
    m_mapGeocode.m_veambiguouslist.Show = noop;
    m_mapGeocode.ShowMessage=noop;
    m_mapGeocode.LoadMap();
    


    //plot all contacts pushpins
    this.plotContacts =  function(p_contacts, p_callback) {
    
        var splashError="";
        var noPlotMsg="";
    
        m_map.DeleteAllPushpins(); //clear all pushpins (if any)
        m_mapGeocode.Pan(30,30); //move the map so we get an onchangeview event if we replot
	    m_mapGeocode.AttachEvent('onchangeview', gotLatLong); //trap when the map changes
        m_mapGeocode.ShowMessage=noPlot; //trap when an error message happens
        
        m_indexToMap = -1;
        this.contacts = m_arrayOfUserData = p_contacts;
        recursivePlot();


        function recursivePlot() {

            function oopsCallback() {
                hideContacts();
                PlacesControl.find();
	        }

            m_indexToMap++;
            if (m_indexToMap < m_arrayOfUserData.length) {
                m_name = "";
                m_email = "";
                var personalstreet = "";
                var personalcity = "";
                var personalstate = "";
                var personalcountry = "";
                var personalpostalcode = "";

                for (var j in m_arrayOfUserData[m_indexToMap]) {
                    var key = j.toLowerCase();
                    switch(key) {
                        case 'name':            m_name = m_arrayOfUserData[m_indexToMap][j]; break;
                        case 'email':           m_email = m_arrayOfUserData[m_indexToMap][j]; break;
                        case 'personalstreet':  personalstreet = m_arrayOfUserData[m_indexToMap][j]; break;
                        case 'personalcity':    personalcity = m_arrayOfUserData[m_indexToMap][j]; break;
                        case 'personalstate':   personalstate = m_arrayOfUserData[m_indexToMap][j]; break;
                        case 'personalcountry': personalcountry = m_arrayOfUserData[m_indexToMap][j]; break;
                        case 'personalpostalcode':personalpostalcode = m_arrayOfUserData[m_indexToMap][j];break;
                        default: break;
                    }
                }
                m_address = (
                        (personalstreet?", "+personalstreet:"")+ 
                        (personalcity?", "+personalcity:"")+ 
                        (personalstate?", "+personalstate:"")+ 
                        (personalpostalcode?", "+personalpostalcode:"")+ 
                        (personalcountry?", "+personalcountry:"")).substr(2);
                if (!m_address) {
                    splashError += '<div class="oopsName">'+hesc(m_name)+'</div>';
                    splashError += '<div class="oopsDesc">Contact does not contain address information.</div>';

                    //remove this contact from the array                    
                    m_arrayOfUserData.splice(m_indexToMap,1);
                    m_indexToMap--;
                    recursivePlot();
                } else {
                    if (!personalstreet) {
                        splashError += '<div class="oopsName">'+hesc(m_name)+'</div>';
                        splashError += '<div class="oopsDesc">Contact mapped at ' + "'" + hesc(m_address) +  "'" + ' which may be approximate due to missing street level information.</div>';
                    }
                    m_mapGeocode.FindLocation(m_address);
                }
            } else {
                //done plotting contacts

                //stop trapping events                
    	        m_mapGeocode.DetachEvent('onchangeview', gotLatLong);
                m_mapGeocode.ShowMessage=noop;

                //center the visible map
                var locs=[];
                for (var i=0;i<m_map.pushpins.length; i++){
                    locs.push(m_map.pushpins[i].LatLong);
                }
                if (locs.length>0) {
                    m_map.SetMapView(locs);
                    if (splashError) {
                        showContacts();
                        Splash.show("oops...", "<p>There was a problem plotting the following contacts. " +
                            "Use Windows Live Contacts&trade; to edit them and press <b>Send selected contacts</b> to try again. " +
                            "Or to ignore and continue, click <b>OK</b>.</p>" +
                            splashError, null, true, oopsCallback);
                    } else {
                        PlacesControl.find();
                    }
                } else {
                    showContacts();
                    Splash.show("oops...", "<p><b>At least one contact must contain address information.</b> "+
                        "Use Windows Live Contacts&trade; to edit your contacts and press <b>Send selected contacts</b> to try again.</p>" +
                        splashError);
                }
            }
        }

        // we get called here when the map moves. unfortunately, VE *MAY* call ShowMessage
        // (which we trap as noPlot) AFTER it does this callback. so...
        // we delay 1 msec so that the call to noPlot can take place.
        function gotLatLong() {
            setTimeout(gotLatLongDelay, 1);
        }
        
        function gotLatLongDelay() {
		
            if (noPlotMsg) {
                noPlotMsg = noPlotMsg.replace(/If the closest match.*/,"");
                splashError += '<div class="oopsName">'+hesc(m_name)+'</div>';
                splashError += '<div class="oopsDesc">'+hesc(noPlotMsg)+'</div>';
                noPlotMsg = null;
            }
       
            latlong = m_mapGeocode.GetCenter();
            
            m_arrayOfUserData[m_indexToMap].latlong = latlong;

            var title = hesc(m_name);
            var description = "<p>"+hesc(m_address)+"</p>"+
                (m_email ? 
                    "<nobr>" +
                    "Messenger " +
                    "<a href='msnim:chat?contact=" + hescq(m_email) + "'>Chat</a> " +
                    "<a href='msnim:voice?contact=" + hescq(m_email) + "'>Voice</a> " +
                    "<a href='msnim:video?contact=" + hescq(m_email) + "'>Video</a>" +
                    "</nobr>" : "");
            var pin = new VEPushpin(
                m_indexToMap + m_name, 
                latlong,
                "images/tdot.gif",
                title,
                description,
                "pushpinCommon"+" "+"contactPushpin"+" "+alphaClass,
                "contactPushpinTitle",
                "contactPushpinDescription" );
            m_map.AddPushpin(pin);
            recursivePlot();
        }

        function noPlot(m_msg) {
            noPlotMsg = m_msg;
        }
    };


    this.getRoutes = function(p_loc, p_callback) {
    
        var routeStr="";

        m_mapGeocode.ShowMessage=noPlot; //trap when an error message happens
        
		m_indexToMap = -1;
		m_destination = p_loc;
		recursiveGetRoute();

	    function recursiveGetRoute() {
	        var url, mailto, mtUrl, msg;
	        m_indexToMap++;
            if (m_indexToMap < m_arrayOfUserData.length) {
                m_mapGeocode.DeleteAllPushpins();
			    m_mapGeocode.GetRoute(m_arrayOfUserData[m_indexToMap].latlong, m_destination.LatLong, VEDistanceUnit.Miles, VERouteType.Shortest, onGetRoute);
		    } else {
			    m_mapGeocode.ShowMessage=noop;
                var enc = new VELatLongEncoding();
                var lldest = enc.Encode(m_destination.LatLong.Latitude, m_destination.LatLong.Longitude);
			    m_arrayOfUserData.sort(sortDistance);

			    mailto = "mailto:{0}?subject={1}&body={2}";
			    for (var i = 0; i < m_arrayOfUserData.length; i ++) {

					if (m_arrayOfUserData[i].distance == -1) {
						routeStr += '<div class="routeName"><b>{0}</b> (unable to map directions)</div>'.format(hesc(m_arrayOfUserData[i].name));
					} else {
						url = "http://" + window.location.host + window.location.pathname +
							"#lls=" + enc.Encode(m_arrayOfUserData[i].latlong.Latitude, m_arrayOfUserData[i].latlong.Longitude) +
							"&lld=" + lldest +
 							"&n=" + encodeURIComponent(m_destination.Name) +
							"&g=" + encodeURIComponent(m_destination.guid);

						msg = m_arrayOfUserData[i].email + ",\n\n" + "Want to get together at " + p_loc.Name + "? It is located at " + p_loc.Description + ".\n\nClick on the URL below for personalized driving directions:\n" + url;
						mtUrl = mailto.format(m_arrayOfUserData[i].email, encodeURIComponent("Meet at "+p_loc.Name+"?"), encodeURIComponent(msg) );
						routeStr += '<div class="routeName"><b>{1}</b> ({2} miles) <a href="{0}" title="Email Directions">Email</a> <a target="_blank" href="{3}" title="See what they will see">Preview</a></div>'.format(mtUrl, hesc(m_arrayOfUserData[i].name), m_arrayOfUserData[i].distance, url);
					}
			    }
			    Splash.show("done",
			        "<p><b>Start the party.</b></p>" +
			        "<p>Click each link below to email the personalized driving directions to your friends. " +
			        "Then get out and have some fun!</p>" +
			        routeStr);
		    }
	    }
    	
        function sortDistance(a, b) {
            return b.distance - a.distance;
        }

		//route successfully plotted
	    function onGetRoute(p_route) {
	        m_arrayOfUserData[m_indexToMap].distance = p_route.Itinerary.Distance;
	        recursiveGetRoute();
	    }
	    
	    //error getting driving directions
        function noPlot(m_msg) {
	        m_arrayOfUserData[m_indexToMap].distance = -1; //mark as error
            recursiveGetRoute(); //continue
        }
    	
	};


	this.findPlace = function(p_query, p_callback) {
	
		if (p_query) {
		    m_map.Find(p_query, "", 1, gotWhatResults);
		} else {
			gotWhatResults([]); //fake the callback
		}

	    
	    function gotWhatResults(p_results) {
	        var locs = [];
	        for (var i=0; i<p_results.length; i++) {
	            var res=p_results[i];
	            if (res.ID) {
	                m_map.DeletePushpin(res.ID);
	                //copy VEFindResult object
	                var loc={};
	                loc.ID = "ps__" + pinId++; //res.ID;
	                loc.guid = res.ID;
	                loc.Name = res.Name;
	                loc.Description = res.Description;
	                loc.LatLong = new VELatLong(res.LatLong.Latitude, res.LatLong.Longitude);
                    locs.push(loc);
	            }
	        }
	        if(p_callback) {p_callback(locs);}
	    }
	    
	};

    //private functions
    function noop() {}

}

//-----------------------------------------------
//utility functions
//-----------------------------------------------

function hesc(p_str) {
    return p_str.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
}
function hescq(p_str) {
    return p_str.replace(/&/g,"&amp;").replace(/</g, "&lt;").replace(/>/g,"&gt;").replace(/\"/g,"&quot;").replace(/\'/g,"&apos;"); 
}


function browserSupportsAlphaNatively() {
    if (document.body.style.filter === undefined) {
        return true; //dosn't support IE's CSS "filter" so assume native support for png alpha
    } else {
        //if IE7 use native support not filter (although both will work)
        var re = /MSIE (\d*)\.(\d*)/;
        var vs = re.exec(window.navigator.appVersion);
        return (parseInt(vs[1]) >= 7); //if major browser verion if < IE7
    }
}



function setAlpha(p_el) {
    if (typeof p_el == "string") {
        p_el = document.getElementById(p_el);
    }
    if (p_el) {
        p_el.className += (browserSupportsAlphaNatively()?" browserAlpha":" browserNoAlpha");
    }
}

function getArgs() {
    //get the arguments from the hash (i.e. http://domain.com/file.htm#this_is_this_hash)
    var args = {};
    var nv, _name, _value;
    if (window.location.hash.substr(0,1)=="#") {
        var keyVals = window.location.hash.substr(1).split("&");
        for (var i=0; i<keyVals.length; i++) {
            nv = keyVals[i].split("=");
            if (nv.length==2) {
                _name =  nv[0];
                _value =  decodeURIComponent(nv[1]);
                args[_name] = _value;
            }
        }
    }
    return args;
}

//returns a location object given an ID
function getLocationById(p_id) {
    for(var i=0; i<places.length; i++) {
        var place = places[i];
        for (var j=0; j<place.locs.length; j++) {
            if (place.locs[j].ID == p_id) {return place.locs[j];}
        }
    }
    return null;
}

function hidePlaceLocations(p_place) {
    for (var i=0; i<p_place.locs.length; i++) {
        try {
        ps.map.DeletePushpin(p_place.locs[i].ID);
        } catch(ex) {}
    }
}

function showPlaceLocations(p_place) {
    var pin, loc;
    for(var i=0; i<p_place.locs.length; i++) {
        loc = p_place.locs[i];
        pin = new VEPushpin(
            loc.ID,
            loc.LatLong,
            "images/tdot.gif", //p_place.icon,
            hesc(loc.Name),
            hesc(loc.Description) +
            (loc.guid?'<br /><a href="http://local.live.com/details.aspx?dt=yp.'+loc.guid+'&style=r" target="_blank">Details</a>' : "<br />") +
            '<br /><input type="button" onclick="setDestination('+ "'" + loc.ID + "'"  +');" value="Set Destination" />',
            "pushpinCommon"+" "+p_place.className+" "+alphaClass,
            "placePushpinTitle",
            "placePushpinDescription" );
        ps.map.AddPushpin(pin);
    }
}


//user clicked "Find" in the Places window
function goFind() {
    
    //clear all pushpins within all places and build the "where" string
    var s="";
    for(var i=0; i<places.length; i++) {
        var place = places[i];
        hidePlaceLocations(place); //delete all of the pushpins
        place.locs=[]; //and remove from the array
        if (place.checked) {
            s += ", "+place.title;
        }
    }
    s = s.substr(2);
    var lc=s.lastIndexOf(",");
    if (lc>=0) {
        s = s.substr(0,lc) + " and" + s.substr(lc+1);
    }

    Splash.show("working", '<p>We are working hard to find '+hesc(s)+' near the location centered on the map.</p>' +            '<p><img src="images/animated_loading.gif" style="width:16px; height:16px; vertical-align:middle;padding-right:5px;" alt="loading..." />' +
            'Locating...</p>');

    
    var placeIdx=-1; //start at the begining
    findPlace(); //find each place
    
    function findPlace(p_callback) {
		var place;
        placeIdx++;
        if (placeIdx < places.length) {
            place = places[placeIdx];
            ps.findPlace(place.query, placeCallback);
        } else {
            PlacesControl.updateCounts();

            if (skipFindConfirmation) {
                Splash.hide();
            } else {
                skipFindConfirmation=true;
                //compute a string with each place and the number of locations
                var s="";
                for(var i=0; i<places.length; i++) {
                    place = places[i];
                    if (place.checked) {
                        s += ", "+place.locs.length+" "+place.title;
                    }
                }
                s = s.substr(2);
                var lc=s.lastIndexOf(",");
                if (lc>=0) {
                    s = s.substr(0,lc) + " and" + s.substr(lc+1);
                }

                PlacesControl.show();
                Splash.show("step 2",
                    "<p><b>Select a place to meet.</b></p>" +
                    "<p>We have automatically plotted the top 10 Restaurants, Bars/Lounges and Coffee Houses on the map.</p>" +
                    "<p>Hover over a push pin to reveal more information. Click 'Set Destination' to choose a meeting place.</p>" +
                    "<p>Don't like the results? Try repositioning the map or changing the checked places and click 'Find'," +
                    " or Right-Click on the map to select your own destination.</p>",
                    null,true);
            }

            if (p_callback) {p_callback();}
        }
        function placeCallback(p_locs) {
            var place = places[placeIdx];
            place.locs=p_locs;
            if (place.checked) {
                showPlaceLocations(place); //plot places
            }
            if (p_callback) {p_callback(place);}
            findPlace(); //find the next place
        }
    }
}


var PlacesControl = new function() {

    var that = this;
    var m_el;
    var m_places;
    var m_hidden = true;
    
    function onCheckClick(p_event, p_place) {
        if (!p_event) {p_event=window.event;}
        var el = p_event.srcElement ? p_event.srcElement : p_event.target;

        p_place.checked = el.checked;

        if (el.checked) {
            showPlaceLocations(p_place); //plot places
        } else {
            hidePlaceLocations(p_place); //delete all of the pushpins
        }
        
    }
    
    function onOtherBlur(p_event, p_place) {
        if (!p_event) {p_event=window.event;}
        var el = p_event.srcElement ? p_event.srcElement : p_event.target;

        p_place.query = el.value;
        p_place.title = "Other ("+hesc(p_place.query)+")";
    }

    this.initalize = function(p_el, p_places) {
        var i, dl, dd, chk, btns, place;
        
        if (typeof p_el == "string") {
            m_el = document.getElementById(p_el);
        } else {
            m_el = p_el;
        }
        
        m_places = p_places;
        
        var el;
        el = document.createElement("div");
        el.className = "title";
        el.innerHTML = "Places";
        m_el.appendChild(el);
        
        dl = document.createElement("dl");

        for(i=0; i<m_places.length; i++) {
            place = m_places[i];
            if (place.title) {
            
				dd = document.createElement("dd");
				dl.appendChild(dd);
	            
				chk = document.createElement("input");
				chk.type="checkbox";
				chk.onclick=onCheckClickFn(place);
				chk.defaultChecked = place.checked;
				dd.appendChild(chk);
	            
				lbl = document.createElement("label");
				//el.for = chk;
				lbl.htmlFor = chk.uniqueID;

					el = document.createElement("span");
					el.className = "text";
					el.innerHTML = hesc(place.title);
					lbl.appendChild(el);

					el = document.createElement("span");
					el.className = "count";
					lbl.appendChild(el);
					place.countEl = el;

				dd.appendChild(lbl);

				if (!place.query) {
					el = document.createElement("br");
					dd.appendChild(el);

					el = document.createElement("input");
					el.type="text";
					el.className="textbox";
					el.onblur=onBlurFn(place);
					dd.appendChild(el);
				}
			}
        }

        m_el.appendChild(dl); //and finally add it to the DOM
        
        btns = document.createElement("div");
        btns.className = "buttons";
        
        el = document.createElement("button");
        el.onclick = goFind;
        el.innerHTML = "Find";
        btns.appendChild(el);
        
        m_el.appendChild(btns);
        
        function onCheckClickFn(p_place) {
            return function(p_event) {
                onCheckClick(p_event, p_place);
            };
        }
        
        function onBlurFn(p_place) {
            return function(p_event) {
                onOtherBlur(p_event, p_place);
            };
        }
    };
    
    this.dispose = function() {
        if (m_timer) {clearTimeout(m_timer);} //stop if running
        m_timer=splashEl=splashTitleEl=splashTextEl=splashButtonEl=null;
    };

    this.show = function() {
        m_el.style.visibility="visible";
        m_hidden=false;
    };

    this.hide = function() {
        hide();
    };
    function hide() {
        m_el.style.visibility="hidden";
        m_hidden=true;
    }
    this.isHidden = function() {
		return m_hidden;
    };

    this.updateCounts = function() {
        var i, place;
        for(i=0; i<m_places.length; i++) {
            place = m_places[i];
            if (place.countEl) {
				place.countEl.innerHTML = "(" + place.locs.length + ")";
            }
        }
    };

    this.find = function() {
        goFind();
    };
    this.getEl = function() {
        return m_el;
    };

    
};

var Splash = new function() {

    var splashEl, splashInnerEl, splashTitleEl, splashTextEl, splashButtonEl;

    var that=this;
    var m_timer;
    var m_onClose;
    
    this.title="";
    this.text="";
    
    this.initalize = function(p_el) {
 
        if (typeof p_el == "string") {
            p_el = document.getElementById(p_el);
        }
 
        setAlpha(p_el);

        var el;

        splashEl = p_el;
        splashEl.style.top=splashEl.style.left=""; //let CSS control top/left

        splashInnerEl = document.createElement("div");
        splashInnerEl.className = "splashInner";
        splashInnerEl.style.zIndex = splashEl.style.zIndex;

        splashTitleEl = document.createElement("div");
        splashTitleEl.className = "splashTitle";
        splashInnerEl.appendChild(splashTitleEl);

        splashTextEl = document.createElement("div");
        splashTextEl.className = "splashText";
        splashInnerEl.appendChild(splashTextEl);

        splashButtonEl = document.createElement("div");
        splashButtonEl.className = "splashButton";
        splashInnerEl.appendChild(splashButtonEl);

        el = document.createElement("button");
        el.innerHTML="OK";
        el.onclick=hide;
        splashButtonEl.appendChild(el);

        hide();

        //and finally, add the whole thing to the DOM
        document.body.appendChild(splashInnerEl);
    };
    
    this.dispose = function() {
        if (m_timer) {clearTimeout(m_timer);} //stop if running
        m_timer=splashEl=splashTitleEl=splashTextEl=splashButtonEl=null;
    };

    this.show = function(p_title, p_msg, p_secs, p_showCloseButton, p_onClose) {

        if (m_timer) {clearTimeout(m_timer);} //stop if running

        splashEl.style.top=splashEl.style.left=""; //let CSS control top/left

        m_onClose = p_onClose;
        splashTitleEl.innerHTML = p_title;
        splashTextEl.innerHTML = p_msg;
        splashButtonEl.style.display = (p_showCloseButton?"block":"none"); //display close button?
        splashEl.style.display="block";
        splashInnerEl.style.display="block";
        splashEl.style.visibility="visible";

        //setup an auto close timer?
        if (p_secs) {
            m_timer = setTimeout(hide, p_secs*1000);
        }
        
    };

    this.hide = function(p_secs, p_showCloseButton, p_onClose) {
        if (m_timer) {clearTimeout(m_timer);} //stop if running
        
        splashButtonEl.style.display = (p_showCloseButton?"block":"none"); //display close button?

        //setup an auto close timer?
        if (p_secs) {
            m_timer = setTimeout(hide, p_secs*1000);
        } else {
            hide();
        }
        
        
    };
    function hide() {
        if (m_timer) {clearTimeout(m_timer);} //stop if running
        splashEl.style.display="none"; //hide the control
        splashInnerEl.style.display="none"; //hide the control
        splashEl.style.visibility="hidden";
        if (m_onClose) {
            var tmpFn = m_onClose;
            m_onClose=null;
            tmpFn();
        }
    }

};


function onMapClick(p_mapEvent) {


	if (event.button==2 && !PlacesControl.isHidden() ) { //right click?

		var latLong = p_mapEvent.view.LatLong;

		//delete old pushpin
		hidePlaceLocations(myPlace); //delete all of the pushpins

		var locs=[];
        var loc={};
        loc.ID = "p_myPlace";
        loc.guid = "";
        loc.Name = "User Defined";
        loc.Description = "";
        loc.LatLong = new VELatLong(latLong.Latitude, latLong.Longitude);
        locs.push(loc);

        myPlace.locs=locs;
        showPlaceLocations(myPlace); //plot places

	}

    function placeCallback(p_locs) {
        var place = places[placeIdx];
        place.locs=p_locs;
        if (place.checked) {
            showPlaceLocations(place); //plot places
        }
        if (p_callback) {p_callback(place);}
        findPlace(); //find the next place
	}

}


//page init
function pageLoad() {
	var el;

    //"alpha-tize" all of the png images (i.e. so 24bit PNG alpha layer works with IE6)
    alphaClass = (browserSupportsAlphaNatively()?"browserAlpha":"browserNoAlpha"); //for push pins
    setAlpha("myLogo");

    el = document.getElementById("myHeader");
	var top = el.offsetHeight;
    setAlpha(el);
	el.onselectstart = function () { return false; }; //keep IE from selecting text if we drag on the header

    myContactsEl = document.getElementById("ContactsControl");
    
    myPlacesEl = document.getElementById("myPlaces");
    butContactsEl = document.getElementById("butContacts");
    butContactsEl.attachEvent('onclick', reSelectContacts);

    try {

        ps = new PartyStarter("myMap"); 
        ps.map.AddControl(myContactsEl); 
        ps.map.AddControl(document.getElementById("myHeader"));
        ps.map.AddControl(document.getElementById("mySplash")); 
        
        ps.map.AttachEvent('onclick', onMapClick); //trap when the user clicks on the map

        //setup our control instances
        Splash.initalize("mySplash");
        PlacesControl.initalize("myPlaces", places);
        var args = getArgs();

        //is there a route given on the url?
		if (args.lls && args.lld) {

            Splash.show("welcome",                     '<p>This sample "mash up" application highlights two cool Microsoft technologies available to third party developers:</p> ' +                    '<p><span class="nowrap">Virtual Earth&trade;</span> and <span class="nowrap">Windows Live Contacts&trade;.</span></p>' +                    '<p>Click Ok below to view your personalized driving directions to '+hesc(args.n)+'</p>',null,true);

            // disable reaction to the contact control	
            myContactsEl.setAttribute("devlive:onData", "");
            myContactsEl.setAttribute("devlive:onSignin", "");
            myContactsEl.setAttribute("devlive:onSignout", "");
            myContactsEl.setAttribute("devlive:onError", "");
            
            var enc = new VELatLongEncoding();
            var lls=enc.Decode(args.lls);
            var lld=enc.Decode(args.lld);
            lls=new VELatLong(lls[0], lls[1]);
            lld=new VELatLong(lld[0], lld[1]);
			ps.map.GetRoute(lls, lld, null, null, null);

		} else {

            Splash.show("welcome", '<p>This sample "mash up" application highlights two cool Microsoft technologies available to third party developers:</p> ' +                    '<p><span class="nowrap">Virtual Earth&trade;</span> and <span class="nowrap">Windows Live Contacts&trade;.</span></p>' +                    '<p><img src="images/animated_loading.gif" style="width:16px; height:16px; vertical-align:middle;padding-right:5px;" alt="loading..." />' +
                    'Loading contacts...</p>');
            
        }
        
		//setup VE dashboard
		var dsb = document.getElementById("myMap_dashboard");
		dsb.style.top = top + "px";
		dsb.style.left = "10px";
		
		myContactsEl.style.top = ""; //reset

		//reposition things and setup to do so when screen width changes
		updateContactLayout();
        window.attachEvent('onresize', updateContactLayout);


    } catch(e) {
        alert(e.message);
    }
}

function pageUnload() {

    butContactsEl.detachEvent('onclick', reSelectContacts);
    myContactsEl = myPlacesEl = butContactsEl = null;
    window.detachEvent('onload', pageLoad);
    window.detachEvent('onunload', pageUnload);
}

function createDestPushpin(p_loc) {
    var pin = new VEPushpin(
        p_loc.ID,
        p_loc.LatLong,
        "images/tdot.gif", //p_place.icon,
        hesc(p_loc.Name),
        hesc(p_loc.Description),
        "pushpinCommon"+" "+"destinationPushpin"+" "+alphaClass,
        "placePushpinTitle",
        "placePushpinDescription" );
    ps.map.AddPushpin(pin);
}


function setDestination(p_id) {

    PlacesControl.hide();

    //hide ALL pins	
    for(var i=0; i<places.length; i++) {
        var place = places[i];
        hidePlaceLocations(place); //delete all of the pushpins
    }

    var loc = getLocationById(p_id); //get the location object
    
    //make a new pushpin
    createDestPushpin(loc);

    Splash.show("directions", '<p>We are now preparing personalized driving directions for each of your contacts. How cool is that?</p>' +            '<p><img src="images/animated_loading.gif" style="width:16px; height:16px; vertical-align:middle;padding-right:5px;" alt="loading..." />' +
            'Preparing Directions...</p>');

	ps.getRoutes(loc);

}


function showContacts() {
	butContactsEl.className="butContactsOff";
	
	slideContacts();
	function slideContacts() {
	    if (butContactsEl.className == "butContactsOff") {
            var y = myContactsEl.offsetTop;
            if (y<94) {
                myContactsEl.style.top = (y+50) + "px";
                setTimeout(slideContacts,50);
            } else {
        	    butContactsEl.title="Hide Contacts";
            }
        }
	}
	
}
function hideContacts() {
	butContactsEl.className="butContactsOn";

	slideContacts();
	function slideContacts() {
	    if (butContactsEl.className == "butContactsOn") {
            var y = myContactsEl.offsetTop;
            if (y>-344) {
                myContactsEl.style.top = (y-50) + "px";
                setTimeout(slideContacts,50);
            } else {
        	    butContactsEl.title="Show Contacts";
            }
        }
	}
}

function reSelectContacts() {
    signIn(); //fake it to get contacts to redisplay
}

function signIn() {
	skipFindConfirmation=false;
    showContacts();
    Splash.show("step 1", 
    "<p><b>Select the people you'd like to bring together.</b></p>"+
    "<p>Windows Live Contacts&trade; allows you to share " +
    "your Windows Live Messenger&trade; or Hotmail&trade; contact information with third party applications, like this one. " +
    "You can also add new contacts or update your current contacts.</p>");
}

function signOut() {
    showContacts(); 
    Splash.show("sign in", 
    "<p>Before we can begin, you must first sign in to Windows Live Contacts&trade; using your Windows Live ID&trade;.</p>");
}

function error() {
    hideContacts();
	butContactsEl.className="butContactsOff"; //hide the "reenter contacts" button too
    Splash.show("oops...","Sorry. The Windows Live Contacts&trade; service is down. Please try again later.");
}

function receiveData(p_contacts) {
    hideContacts(); 
    ps.plotContacts(p_contacts);
}

//fixup the left of some elements based off of the new screen width (called on resize)
function updateContactLayout() {

    var ww = getWindowWidth();

    myContactsEl.style.left = (ww - 10 - myContactsEl.offsetWidth) + "px";

    var el = PlacesControl.getEl();
    el.style.left = (ww - 10 - el.offsetWidth) + "px";
    
	//reselect contact button
    butContactsEl.style.left = (ww - 15 - 99) + "px";

}
function getWindowWidth(){
    if(window.innerWidth) {return window.innerWidth;}
    else if(document.documentElement && document.documentElement.clientWidth) {return document.documentElement.clientWidth;}
    else if(document.body && document.body.clientWidth) {return document.body.clientWidth;}
    else {return 0;}
}




window.attachEvent('onload', pageLoad);
window.attachEvent('onunload', pageUnload);
